package trackClustering.example.behavior;


import trackClustering.example.entity.TrajectoryPoint;

import java.util.*;
import java.util.stream.Collectors;

public class TrajectoryProcessByBehaviorDTW {
    private final double distanceThreshold; // 层次聚类的距离阈值
    private final int minClusterSize; // 最小簇点数

    public TrajectoryProcessByBehaviorDTW(double distanceThreshold, int minClusterSize) {
        this.distanceThreshold = distanceThreshold;
        this.minClusterSize = minClusterSize;
    }

    // 核心聚类方法
    public Map<Integer, Map<Integer, List<TrajectoryPoint>>> clusterBySpatialClusters(
            Map<Integer, List<TrajectoryPoint>> spatialClusters) {
        Map<Integer, Map<Integer, List<TrajectoryPoint>>> result = new HashMap<>();

        for (Map.Entry<Integer, List<TrajectoryPoint>> entry : spatialClusters.entrySet()) {
            int spatialClusterId = entry.getKey();
            List<TrajectoryPoint> spatialCluster = entry.getValue();

            if (spatialCluster.size() < minClusterSize) {
                continue;
            }

            // 提取轨迹序列并计算DTW聚类
            List<BehaviorFeature> features = extractBehaviorFeatures(spatialCluster);
            List<List<BehaviorFeature>> trajectories = Arrays.asList(features);
            // 当前仅处理单轨迹
            List<List<TrajectoryPoint>> behaviorClusters = hierarchicalCluster(trajectories);

            // 转换为结果格式
            Map<Integer, List<TrajectoryPoint>> behaviorMap = new HashMap<>();
            int clusterId = 1;
            for (List<TrajectoryPoint> cluster : behaviorClusters) {
                behaviorMap.put(clusterId++, cluster);
            }
            result.put(spatialClusterId, behaviorMap);
        }
        return result;
    }

    // 特征提取（空间差分+时间+速度标准化）
    private List<BehaviorFeature> extractBehaviorFeatures(List<TrajectoryPoint> points) {
        List<TrajectoryPoint> sortedPoints = points.stream()
                .sorted(Comparator.comparingLong(TrajectoryPoint::getTimeStamp))
                .collect(Collectors.toList());

        List<BehaviorFeature> features = new ArrayList<>();
        for (int i = 0; i < sortedPoints.size(); i++) {
            TrajectoryPoint p = sortedPoints.get(i);
            double deltaX = i == 0 ? 0 : (p.getLongitude() - sortedPoints.get(i - 1).getLongitude());
            double deltaY = i == 0 ? 0 : (p.getLatitude() - sortedPoints.get(i - 1).getLatitude());

            // 标准化时间与速度
            double timeMean = calculateMean(sortedPoints.stream()
                    .mapToLong(TrajectoryPoint::getTimeStamp).boxed().collect(Collectors.toList()));
            double timeStd = calculateStd(sortedPoints.stream()
                    .mapToLong(TrajectoryPoint::getTimeStamp).boxed().collect(Collectors.toList()));
            double time = (p.getTimeStamp() - timeMean) / (timeStd == 0 ? 1 : timeStd);

            double speedMean = calculateMean(sortedPoints.stream()
                    .mapToDouble(TrajectoryPoint::getHorizontalSpeed).boxed().collect(Collectors.toList()));
            double speedStd = calculateStd(sortedPoints.stream()
                    .mapToDouble(TrajectoryPoint::getHorizontalSpeed).boxed().collect(Collectors.toList()));
            double speed = (p.getHorizontalSpeed() - speedMean) / (speedStd == 0 ? 1 : speedStd);

            features.add(new BehaviorFeature(p, deltaX, deltaY, time, speed));
        }
        return features;
    }

    // 动态时间规整（DTW）距离计算
    private double dtwDistance(List<BehaviorFeature> traj1, List<BehaviorFeature> traj2) {
        int n = traj1.size(), m = traj2.size();
        double[][] cost = new double[n + 1][m + 1];
        for (int i = 0; i <= n; i++) {
            Arrays.fill(cost[i], Double.POSITIVE_INFINITY);
        }
        cost[0][0] = 0;

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                double dist = distance(traj1.get(i - 1), traj2.get(j - 1));
                cost[i][j] = dist + Math.min(
                        Math.min(cost[i - 1][j], cost[i][j - 1]),
                        cost[i - 1][j - 1]
                );
            }
        }
        return cost[n][m];
    }

    // 特征向量欧氏距离
    private double distance(BehaviorFeature a, BehaviorFeature b) {
        double[] aVec = a.getFeatures();
        double[] bVec = b.getFeatures();
        double sum = 0;
        for (int i = 0; i < aVec.length; i++) {
            sum += Math.pow(aVec[i] - bVec[i], 2);
        }
        return Math.sqrt(sum);
    }

    // 层次聚类实现
    private List<List<TrajectoryPoint>> hierarchicalCluster(List<List<BehaviorFeature>> trajectories) {
        // 假设输入 trajectories 是单个空间簇的轨迹序列
        List<BehaviorFeature> features = trajectories.get(0);
        List<TrajectoryPoint> points = features.stream()
                .map(BehaviorFeature::getPoint)
                .collect(Collectors.toList());

        // 计算所有点之间的DTW距离矩阵（简化为单轨迹的特征相似度）
        double[][] distanceMatrix = new double[points.size()][points.size()];
        for (int i = 0; i < points.size(); i++) {
            for (int j = 0; j < points.size(); j++) {
                distanceMatrix[i][j] = distance(features.get(i), features.get(j));
            }
        }

        // 层次聚类步骤（简化版：按距离阈值分割）
        List<List<TrajectoryPoint>> clusters = new ArrayList<>();
        boolean[] assigned = new boolean[points.size()];
        for (int i = 0; i < points.size(); i++) {
            if (!assigned[i]) {
                List<TrajectoryPoint> cluster = new ArrayList<>();
                cluster.add(points.get(i));
                assigned[i] = true;
                for (int j = i + 1; j < points.size(); j++) {
                    if (!assigned[j] && distanceMatrix[i][j] <= distanceThreshold) {
                        cluster.add(points.get(j));
                        assigned[j] = true;
                    }
                }
                clusters.add(cluster);
            }
        }

        // 合并小簇（确保每个簇至少有 minClusterSize 点）
        List<List<TrajectoryPoint>> filteredClusters = new ArrayList<>();
        for (List<TrajectoryPoint> cluster : clusters) {
            if (cluster.size() >= minClusterSize) {
                filteredClusters.add(cluster);
            }
        }

        // 验证覆盖完整路线（确保每个簇的轨迹点按时间顺序覆盖原路径）
        return filterCompleteRoutes(filteredClusters, points);
    }
    private List<List<TrajectoryPoint>> filterCompleteRoutes(
            List<List<TrajectoryPoint>> clusters, List<TrajectoryPoint> originalPoints) {
        List<List<TrajectoryPoint>> validClusters = new ArrayList<>();
        for (List<TrajectoryPoint> cluster : clusters) {
            if (isPathCovered(cluster, originalPoints)) {
                validClusters.add(cluster);
            }
        }
        return validClusters.isEmpty()
                ? Collections.singletonList(originalPoints)
                // 不可变列表
                : validClusters;
    }

    private boolean isPathCovered(List<TrajectoryPoint> cluster, List<TrajectoryPoint> original) {
        // 检查簇的起始和结束时间是否与原轨迹一致
        return cluster.get(0).getTimeStamp() == original.get(0).getTimeStamp() &&
                cluster.get(cluster.size()-1).getTimeStamp() == original.get(original.size()-1).getTimeStamp();
    }
    // 辅助方法：均值计算
    private double calculateMean(List<? extends Number> values) {
        return values.stream().mapToDouble(Number::doubleValue).average().orElse(0);
    }

    // 辅助方法：标准差计算
    private double calculateStd(List<? extends Number> values) {
        double mean = calculateMean(values);
        return Math.sqrt(values.stream()
                .mapToDouble(v -> Math.pow(v.doubleValue() - mean, 2))
                .sum() / (values.size() - 1));
    }

    // 行为特征类
    private static class BehaviorFeature {
        private final TrajectoryPoint point;
        private final double[] features; // [deltaX, deltaY, normalizedTime, normalizedSpeed]

        public BehaviorFeature(TrajectoryPoint point,
                              double deltaX, double deltaY,
                              double time, double speed) {
            this.point = point;
            this.features = new double[]{deltaX, deltaY, time, speed};
        }

        public TrajectoryPoint getPoint() {
            return point;
        }

        public double[] getFeatures() {
            return features;
        }
    }
}
